package com.insigma.business.qrcode.soldier.util;


import cn.hutool.core.date.DateUtil;
import com.insigma.business.qrcode.common.util.RedisUtils;
import com.insigma.business.qrcode.common.util.SpringContextUtil;
import com.insigma.business.qrcode.soldier.dto.SoldierBasicInfoBSearcher;
import com.insigma.business.qrcode.soldier.entity.SoldierBasicInfoDO;
import com.insigma.business.qrcode.soldier.entity.SoldierTpAllDO;
import com.insigma.business.qrcode.soldier.service.CommonDataDictService;
import com.insigma.business.qrcode.soldier.service.SchedulerJobExec;
import com.insigma.business.qrcode.soldier.service.SoldierBasicInfoService;
import com.insigma.business.qrcode.soldier.service.SoldierTpAllService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;


public class SchedulerJob extends Thread {

    private static Logger LOGGER = LoggerFactory.getLogger(SchedulerJob.class);

    private String PREFIX = "SoldierExtraInfoRefresher";

    private String code;

    private String fatherCode;

    private String jobName;

    private SchedulerJobExec runnable;

    private Integer pageSize = 500;

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private SoldierBasicInfoService soldierBasicInfoService;
    @Autowired
    private SoldierTpAllService soldierTpAllService;

    @Autowired
    private CommonDataDictService commonDataDictService;

    private String taskModule = "JOB";

    private String taskRecordKey = "MAXCOUNT";

    AtomicInteger atomicCount;

    ConcurrentHashMap<String, Future> futureMap;

    ConcurrentLinkedQueue<SoldierBasicInfoDO> queue = new ConcurrentLinkedQueue<SoldierBasicInfoDO>();

    public SchedulerJob(String fatherCode, String jobName, ConcurrentHashMap<String, Future> futureMap, SchedulerJobExec runnable) {
        this.fatherCode = fatherCode;
        this.jobName = jobName;
        this.code = fatherCode + "_" + jobName;
        this.futureMap = futureMap;
        this.runnable = runnable;
        redisUtils = (RedisUtils) SpringContextUtil.getBean("redisUtils");
        soldierBasicInfoService = (SoldierBasicInfoService) SpringContextUtil.getBean("soldierBasicInfoService");
        soldierTpAllService = (SoldierTpAllService) SpringContextUtil.getBean("soldierTpAllService");
    }

    @Override
    public void run() {
        LOGGER.info("线程：{}, code：{} 开始刷新", jobName, code);
        Boolean finished = isFinished(code);
        if (finished) {
            removeFromSchedulerMap(jobName);
            LOGGER.info("*******************FINISH*************,{}, name, {}", code, jobName);
            return;
        }

        try {
            Thread.sleep(new Random(10).nextInt(1000));
        } catch (InterruptedException e) {
            LOGGER.error("err:{}", e);
        }

        while (true) {
            if (queue.isEmpty()) {
                List<SoldierBasicInfoDO> search = getNextList(code);
                if (CollectionUtils.isEmpty(search)) {
                    setFinished(code);
                    removeFromSchedulerMap(code);
                    commonDataDictService.append(taskModule, taskRecordKey, "任务结束:" + DateUtil.format(new Date(), "yyyy:MM:dd HH:mm:ss"));
                    LOGGER.info("*******************FINISH*************", code, "name", jobName);
                    return;
                }
                queue.addAll(search);
            }

            while (!queue.isEmpty()) {
                SoldierBasicInfoDO basicInfoDO = queue.poll();
                LOGGER.info("刷新局部 : {}, loop:{},   idCardNo: {}", jobName, atomicCount.incrementAndGet(), basicInfoDO.getIdCardNo());
                SoldierTpAllDO soldierTpAllDO = soldierTpAllService.getByIdCardNo(basicInfoDO.getIdCardNo());
                try {
                    if (soldierTpAllDO == null) {
                        soldierTpAllDO = new SoldierTpAllDO();
                        soldierTpAllDO.setIdCardNo(basicInfoDO.getIdCardNo());
                        soldierTpAllDO.setNickName(basicInfoDO.getRealName());
                        soldierTpAllService.insert(soldierTpAllDO);
                    }

                    Boolean exec = runnable.exec(soldierTpAllDO);
                    if (exec) {
                        soldierTpAllService.update(soldierTpAllDO);
                    }
                } catch (MaxCountException e) {
                    LOGGER.error("********刷新到达上限，{}，{},{}", jobName, "次数", atomicCount);
                    queue.add(basicInfoDO);
                    return;
                } catch (Exception e) {
                    LOGGER.error("刷新异常：{}", e);
                    return;
                }
            }
        }
    }

    private void removeFromSchedulerMap(String name) {
        Future future = futureMap.get(name);
        if (future != null) {
            future.cancel(true);
            futureMap.remove(name);
        }
    }

    private List<SoldierBasicInfoDO> getNextList(String code) {
        Integer pageNo = getNextPage(code);
        atomicCount = new AtomicInteger(pageSize * (pageNo - 1));
        LOGGER.info("开始刷新,  pageNo:{}", pageNo);
        SoldierBasicInfoBSearcher innerSearcher = new SoldierBasicInfoBSearcher(pageNo, pageSize);
        innerSearcher.setSortKeyValueJoint("id_asc");
        List<SoldierBasicInfoDO> search;
        search = soldierBasicInfoService.search(innerSearcher);
        return search;
    }

    private Integer getNextPage(String code) {
        String key = PREFIX + "_" + code + "_current_page";
        Object o = redisUtils.get(key);
        if (o == null) {
            redisUtils.set(key, 1);
            return 1;
        }
        Integer i = (Integer) o;
        redisUtils.set(key, i + 1);
        return i + 1;
    }

    private boolean isFinished(String code) {
        String key = PREFIX + "_" + code + "_finished";
        Object o = redisUtils.get(key);
        if (o == null) {
            return false;
        }
        return true;
    }

    private void setFinished(String code) {
        String key = PREFIX + "_" + code + "_finished";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm");
        Date now = new Date();
        String nowTime = sdf.format(now);
        LOGGER.info("{}, finished at {}", code, nowTime);
        redisUtils.set(key, nowTime);
    }
}
